package com.yuandian.bpm.bi.modules.quartz.service;

import com.yuandian.bpm.bi.modules.quartz.enums.TaskStateEnum;
import com.yuandian.bpm.bi.modules.quartz.enums.TaskTypeEnum;
import com.yuandian.bpm.bi.modules.quartz.queue.FileInfoStorage;
import com.yuandian.bpm.bi.modules.quartz.queue.LogStorage;
import com.yuandian.bpm.bi.modules.quartz.queue.TaskInfoStorage;
import com.yuandian.bpm.bi.modules.quartz.util.SpringContextJobUtil;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportFileInfo;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskInfo;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskLog;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskVo;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * <p> 任务基类 </p>
 *
 * @Author: LinSheHi
 * @Date: 2022/9/27 17:31
 */
@Slf4j
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class JobBase implements Job {

	/** 保存日志信息 */
	private static final BlockingQueue<ConfReportTaskLog> logInfoQueue = new LinkedBlockingQueue<>();
	/** 保存文件信息 */
	private static final BlockingQueue<ConfReportFileInfo> fileInfoQueue = new LinkedBlockingQueue<>();
	/** 保存任务信息 */
	private static final BlockingQueue<ConfReportTaskInfo> taskInfoQueue = new LinkedBlockingQueue<>();


	/** bean名称 */
    private final String beanName;

	/** 最大重启次数 */
	private int maxRestartCount;

	/** 已经重启次数 */
	private int restartCount;

	/** 重启间距(单位：分钟) */
	private int restartDelay = 0;

	static {
		// 创建日志存储器并启动存储线程
		LogStorage logStorage = new LogStorage(logInfoQueue);
		Thread logStorageThread = new Thread(logStorage);
		logStorageThread.start();

		// 创建文件存储器并启动存储线程
		FileInfoStorage fileInfoStorage = new FileInfoStorage(fileInfoQueue);
		Thread fileStorageThread = new Thread(fileInfoStorage);
		fileStorageThread.start();

		// 创建任务信息存储器并启动更新线程
		TaskInfoStorage taskInfoStorage = new TaskInfoStorage(taskInfoQueue);
		Thread taskInfoStorageThread = new Thread(taskInfoStorage);
		taskInfoStorageThread.start();
	}

	public JobBase(String beanName) { this.beanName = beanName;  }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
		HandelBaseService baseTaskService = (HandelBaseService) SpringContextJobUtil.getBean(beanName);
		ConfReportTaskInfo confReportTaskInfo = (ConfReportTaskInfo) context.getMergedJobDataMap().get("confReportTaskInfo");
		this.maxRestartCount = (confReportTaskInfo.getTaskRestartCount() == null ? 0 : confReportTaskInfo.getTaskRestartCount());
		this.restartDelay = (confReportTaskInfo.getTaskRestartInterval() == null ? 0 : confReportTaskInfo.getTaskRestartInterval());

		// 执行任务逻辑(如果任务有设置 ‘总需执行次数’ 指标时, 则需要比较当前已经执行的次数)
		if (confReportTaskInfo.getTaskTotalExecuteCount() == -1 ||
				confReportTaskInfo.getTaskAlreadyExecuteCount() < confReportTaskInfo.getTaskTotalExecuteCount()) {

			ConfReportTaskVo result = baseTaskService.handleData(confReportTaskInfo, context);

			// 对 报表类 的任务进行 日志保存、任务信息更新、文件信息保存 等操作
			if (TaskTypeEnum.REPORT.toString().equals(result.getTaskType())) {

				try {
					// 保存任务日志
					sayLogInfo(result.getConfReportTaskLog());
					if (result.isTaskFlag()) {
						// 执行成功: 更新任务信息, 保存文件信息
						updateTaskInfo(result.getConfReportTaskInfo());
						sayFileInfo(result.getConfReportFileInfo());
						this.restartDelay = 0;

					} else {
						// 任务执行失败, 重启任务
						restartJob(context, confReportTaskInfo);
					}

				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
				}
			}

		} else {
			// 停止任务
			confReportTaskInfo.setTaskState(TaskStateEnum.ENDED.getCode());
			stopJob(context, confReportTaskInfo);
			log.warn("[任务执行]-任务停止-任务:{} 已'执行'次数: {} 已经达到阈值: {}",
					confReportTaskInfo.getId(),
					confReportTaskInfo.getTaskAlreadyExecuteCount(),
					confReportTaskInfo.getTaskTotalExecuteCount());
		}
	}


	/**
	 * 任务重启
	 * @param context	上下文
	 * @param confReportTaskInfo 参数对象
	 */
	private void restartJob(JobExecutionContext context, ConfReportTaskInfo confReportTaskInfo)
			throws JobExecutionException, InterruptedException {

		if (restartCount < maxRestartCount) {
			// 延迟重启任务
			TimeUnit.MINUTES.sleep(restartDelay);

			log.warn("[任务执行]-任务:{} 重启，当前重启次数: {}, 总重启次数: {}" ,
					confReportTaskInfo.getId(),
					(++restartCount),
					maxRestartCount);

			throw new JobExecutionException(true);
		} else {
			// 停止任务
			confReportTaskInfo.setTaskState(0);
			stopJob(context, confReportTaskInfo);
			log.warn("[任务执行]-任务停止-任务:{} 已'重启'次数: {} 已经达到阈值: {}",
					confReportTaskInfo.getId(),
					confReportTaskInfo.getTaskAlreadyExecuteCount(),
					confReportTaskInfo.getTaskTotalExecuteCount());
		}
	}

	/**
	 * 停止任务
	 * @param context	上下文
	 * @param confReportTaskInfo	任务信息对象
	 */
	private void stopJob(JobExecutionContext context, ConfReportTaskInfo confReportTaskInfo) {
		try {
			// 停止当前任务的触发
			Scheduler scheduler = context.getScheduler();
			scheduler.unscheduleJob(context.getTrigger().getKey());
			scheduler.deleteJob(context.getJobDetail().getKey());

			// 更新任务信息
			updateTaskInfo(confReportTaskInfo);

		} catch (SchedulerException | InterruptedException se) {
			se.printStackTrace();
		}
	}


	/**
	 * 保存文件信息
	 * @param confReportFileInfo	文件信息对象
	 */
	private void sayFileInfo(ConfReportFileInfo confReportFileInfo) throws InterruptedException {
		fileInfoQueue.put(confReportFileInfo);
	}


	/**
	 * 更新任务信息
	 * @param confReportTaskInfo 任务对象
	 */
	private void updateTaskInfo(ConfReportTaskInfo confReportTaskInfo) throws InterruptedException {
		taskInfoQueue.put(confReportTaskInfo);
	}


	/**
	 * 保存日志信息
	 */
	private void sayLogInfo(ConfReportTaskLog confReportTaskLog) throws InterruptedException {
		logInfoQueue.put(confReportTaskLog);
	}
}

